package joc.internal.transformer;

import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import joc.Condition;
import joc.JOCCondition;
import joc.PreCondition;
import joc.internal.compiler.StandaloneExp;
import joc.internal.transformer.helper.BackdoorAnnotationLoader;

public class CustomPreConditionBehaviorTransformer extends DeclaredBehaviorTransformer {

	public CustomPreConditionBehaviorTransformer(Transformer transformer) {
		super(transformer);
	}

	@Override
	public void transform(CtClass clazz, CtBehavior behavior) throws Exception {
		getLogger().info("behavior " + behavior.getLongName());
		if (behavior.hasAnnotation(PreCondition.class)) {
			String[] pcClasses = new BackdoorAnnotationLoader(behavior).getClassArrayValue(PreCondition.class, "value");
			for (String pcClass : pcClasses) {
				applyPreCondition(behavior, transformer.getPool().get(pcClass));
			}
		}
	}

	private void applyPreCondition(CtBehavior behavior, CtClass pcClass) throws Exception {
		if (!pcClass.hasAnnotation(JOCCondition.class)) {
			throw new JOCTransformationException("Pre-Condition " + pcClass.getName()
					+ " must have annotation JOCCondition.");
		}
		String pcClassName = pcClass.getName();
		getLogger().info("behavior " + behavior.getLongName() + " has post-condition " + pcClassName);
		StandaloneExp insertBefore = initializeConditionString(pcClassName);
		for (CtMethod pcMethod : pcClass.getDeclaredMethods()) {
			if (pcMethod.hasAnnotation(Condition.class)) {
				insertBefore = insertBefore.append(callConditionString(pcClass, pcMethod, true, behavior, false));
			}
		}
		getLogger().info("insertBefore: " + insertBefore);
		insertBefore.insertBefore(behavior);
	}

}
